#pragma once

#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"

namespace ThreadPoolMudule
{
	using namespace ThreadModule;
	using namespace LogModule;
	using namespace LockModule;
	using namespace CondModule;

	// 测试线程的方法
	void DefaultTest()
	{
		while (1)
		{
			LOG(LogLevel::DEBUG) << "测试线程";
			sleep(1);
		}
	}

	using thread_t = std::shared_ptr<Thread>;

	const static int defaultnum = 5;

	template <typename T>
	class ThreadPool
	{
	private:
		bool IsEmpty() { return _taskq.empty(); }

		void HandlerTask(std::string name)
		{
			LOG(LogLevel::INFO) << "线程: " << name << ",进入HandlerTask的逻辑";
			while (1)
			{
				// 1. 拿任务
				T t;
				{
					LockGuard lockguard(_mutex);
					while (IsEmpty() && _isrunning)
					{
						_wait_num++;
						_cond.Wait(_mutex);
						_wait_num--;
					}

					// 队列为空，线程池退出
					if (IsEmpty() && !_isrunning)
						break;

					t = _taskq.front();
					_taskq.pop();
				}

				// 2.处理任务
				t(name); // 规定：未来所有的任务处理，全部都是必须提供()方法
			}
			LOG(LogLevel::INFO) << "线程退出";
		}

		ThreadPool(const ThreadPool<T> &) = delete; // 禁掉拷贝构造
		ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // 禁掉赋值

		ThreadPool(int num = defaultnum) // 构造函数设置为私有
			: _num(num), _wait_num(0), _isrunning(false)
		{
			for (auto i = 0; i < _num; i++)
			{
				//_threads.push_back(std::make_shared<Thread>(DefaultTest));
				_threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1)));
				LOG(LogLevel::INFO) << "构建线程" << _threads.back()->Name() << "对象成功";
			}
		}

	public:
		// 懒汉模式实现单例
		static ThreadPool<T> *getInstance()
		{
			// 第一次检查：快速判断实例是否已存在
    	    // 目的：避免每次获取实例都加锁，提升性能（多线程下也只在首次创建时加锁）
			if (instance == NULL) // 双if判断，避免锁冲突概率
			{
				LockGuard lockguard(_lock); // 加锁保护instance和单例对象

				LOG(LogLevel::INFO) << "单例首次被执行，需要加载对象";

				// 第二次检查：防止多线程同时通过外层 if 后，重复创建实例
				if (instance == NULL)
				{
					instance = new ThreadPool<T>(); // 创建唯一实例
				}
			}

			return instance;
		}
		void Equeue(T&& in) // 任务入队列
		{
			LockGuard lockguard(_mutex);
			if (!_isrunning)
				return;
			_taskq.push(std::move(in));

			if (_wait_num > 0)
				_cond.Noticy();
		}

		void Start() // 启动线程池
		{
			if (_isrunning)
				return;
			_isrunning = true;
			for (auto thread_ptr : _threads)
			{
				thread_ptr->Start();
				LOG(LogLevel::INFO) << "启动线程" << thread_ptr->Name() << "...成功";
			}
			_isrunning = true;
		}

		void Wait()
		{
			for (auto &thread_ptr : _threads)
			{
				thread_ptr->Join();
				LOG(LogLevel::INFO) << "停止线程" << thread_ptr->Name() << "...成功";
			}
		}

		void Stop() // 终止线程池
		{
			LockGuard lockguard(_mutex);

			if (_isrunning)
			{
				// 3.线程池不应该再入任务
				_isrunning = false; // 线程池不工作

				// 1.让线程自己退出(要唤醒)   2.保证历史任务被处理完
				if (_wait_num > 0)
					_cond.NoticyAll();
			}
		}

		~ThreadPool()
		{
		}

	private:
		int _num;
		std::queue<T> _taskq;
		int _wait_num;
		std::vector<thread_t> _threads; // 临界资源

		Mutex _mutex;
		Cond _cond;

		bool _isrunning;

		static ThreadPool<T> *instance; // 创建一个全局唯一的 instance 指针
		static Mutex _lock; // 只用来保护单例
	};

	// 模板类静态成员变量的类外初始化，用于初始化单例模式中的唯一实例指针，类的静态成员变量必须在类外单独定义并初始化
	template <typename T>
	ThreadPool<T> *ThreadPool<T>::instance = NULL; // 静态指针，初始化

	template <typename T>
	Mutex ThreadPool<T>::_lock;
};